|
|
EEG - Electrode Placement |
| Tags | record☁eeg☁electrode placement☁snr |
The acquisition of
Electroencephalogram (EEG)
data requires the correct electrode placement for good signal quality. For conventional EEG data acquisitions, electrodes are placed according to the
10-20 system
to measure the electric potentials from the skin.
The potential differences are measured between each electrode and a reference electrode whereas in
bipolar recording
such as the one existent on PLUX"s sensors, the potential difference is measured between adjacent electrodes.
Hence when using a single PLUX EEG sensor with two electrodes, one needs to decide on one specific electrode position of the 10-20 system relating to the desired brain region for data acquisition.
This Jupyter Notebook illustrates the electrode placement for acquiring EEG signals when the researcher wants to extract the alpha band frequencies for the task of closing the eyes and compares the signal quality by measuring the Signal-to-noise ratio (SNR) .
For more information on alpha band extraction as well as SNR please refer to the notebooks:
EEG - Alpha band extraction
and
EEG - Digital filtering
.
1 - Importation of the needed packages
# Biosignalsnotebooks python package
import biosignalsnotebooks as bsnb
# Scientific packages
from numpy import logical_and, trapz
from scipy.signal import welch
2 - Electrode Placement
2.1 - Preparation
Consider the following steps before placing the electrodes at the desired region:
2.2 - Alpha Band Frequency location
For measuring the alpha band frequencies (8-12 Hz), the electrodes are placed on the
occipital (O)
/
parietal (P)
positions due to formation of alpha oscillations in the occipital lobe.
The neutral electrode is placed behind the
ear (M1)
position.
For more information on alpha waves, please refer to the notebook
EEG - Alpha band extraction
.
2.3 - Setup
The following setup of
electrode placements
were tested in order to compare the
signal quality
for measurement of alpha band power.
List of electrode placements used for alpha power detection:
|
|
|
| 1.A | 1.B | 1.B |
|
|
|
| 2.A | ||
|
|
|
| 2.B |
3 - Loading of acquired EEG data and Unit Conversion
For a detailed explanation on how to load the acquired EEG data as well as performing the Unit Conversion of the raw data, please refer to the notebooks
Load acquired data from .txt file
and
EEG-Unit Conversion
A - Electrode Position O1/O2
# Load Data from signal samples library - electrode position O1/O2:
data, header = bsnb.load_signal("eeg_sample_o", get_header=True)
# [The acquired EEG data is at channel 1 ("CH1")]
eeg_data = data["CH1"]
B - P3/P4 Segment
#Load Data from signal samples library
#A: P3/P4 Segment:
data_eeg_p = bsnb.load_signal("eeg_sample_p")
# [The acquired EEG data is at channel 1 ("CH1")]
#A: P3/P4 Segment:
eeg_data_p = data_eeg_p["CH1"]
C - O1/O2 Horizontal Segment
#B:O1/O2 horizontal Segment:
data_eeg_0cm_hor = bsnb.load_signal("eeg_sample_0cm_h")
data_eeg_1cm_hor = bsnb.load_signal("eeg_sample_1cm_h")
data_eeg_2cm_hor = bsnb.load_signal("eeg_sample_2cm_h")
# [The acquired EEG data is at channel 1 ("CH1")]
#B:O1/O2 horizontal Segment:
eeg_data_0cm_hor = data_eeg_0cm_hor["CH1"]
eeg_data_1cm_hor = data_eeg_1cm_hor["CH1"]
eeg_data_2cm_hor = data_eeg_2cm_hor["CH1"]
D - O1/O2 Vertical Segment
#C:O1 vertical Segment:
data_eeg_0cm_ver = bsnb.load_signal("eeg_sample_0cm_v")
data_eeg_1cm_ver = bsnb.load_signal("eeg_sample_1cm_v")
data_eeg_2cm_ver = bsnb.load_signal("eeg_sample_2cm_v")
# [The acquired EEG data is at channel 1 ("CH2")]
#C:O1 vertical Segment:
eeg_data_0cm_ver = data_eeg_0cm_ver["CH2"]
eeg_data_1cm_ver = data_eeg_1cm_ver["CH2"]
eeg_data_2cm_ver = data_eeg_2cm_ver["CH2"]
3.1 - Store acquisition constants
Two extremely relevant parameters defined before data acquisition are the sampling rate and ADC resolution. On one of the previous cells (substep
A
) we only request the
header
of
eeg_sample_o
signal sample because the remaining signal samples were collected in similar conditions (at the same sampling rate and resolution).
sr = header["sampling rate"] # Sampling Rate
resolution = header["resolution"][0]
3.2 - Conversion of ADC sample values to physical units (uV) and generation of a time-axis
The device used to acquire EEG data belongs to the "biosignalsplux" model.
In order to convert the raw EEG signal to its physical units, the recorded data must be passed as an input of
raw_to_phy
function.
A - Electrode Position O1/O2
#Unit Conversion #electrode position O1/O2:
eeg_signal_uv = bsnb.raw_to_phy("EEG", "biosignalsplux", eeg_data, resolution, "uV")
time_eeg_signal_uv = bsnb.generate_time(eeg_signal_uv, sr)
B - P3/P4 Segment
#Unit Conversion
#A: P3/P4 Segment:
eeg_signal_uv_p = bsnb.raw_to_phy("EEG", "biosignalsplux", eeg_data_p, resolution, "uV")
time_eeg_signal_uv_p = bsnb.generate_time(eeg_signal_uv_p, sr)
C - O1/O2 Horizontal Segment
#B:O1/O2 horizontal Segment:
eeg_signal_uv_0cm_hor = bsnb.raw_to_phy("EEG", "biosignalsplux", eeg_data_0cm_hor, resolution, "uV")
time_eeg_signal_uv_0cm_hor = bsnb.generate_time(eeg_signal_uv_0cm_hor, sr)
eeg_signal_uv_1cm_hor = bsnb.raw_to_phy("EEG", "biosignalsplux", eeg_data_1cm_hor, resolution, "uV")
time_eeg_signal_uv_1cm_hor = bsnb.generate_time(eeg_signal_uv_1cm_hor, sr)
eeg_signal_uv_2cm_hor = bsnb.raw_to_phy("EEG", "biosignalsplux", eeg_data_2cm_hor, resolution, "uV")
time_eeg_signal_uv_2cm_hor = bsnb.generate_time(eeg_signal_uv_2cm_hor, sr)
D - O1/O2 Vertical Segment
#C:O1 vertical Segment:
eeg_signal_uv_0cm_ver = bsnb.raw_to_phy("EEG", "biosignalsplux", eeg_data_0cm_ver, resolution, "uV")
time_eeg_signal_uv_0cm_ver = bsnb.generate_time(eeg_signal_uv_0cm_ver, sr)
eeg_signal_uv_1cm_ver = bsnb.raw_to_phy("EEG", "biosignalsplux", eeg_data_1cm_ver, resolution, "uV")
time_eeg_signal_uv_1cm_ver = bsnb.generate_time(eeg_signal_uv_1cm_ver, sr)
eeg_signal_uv_2cm_ver = bsnb.raw_to_phy("EEG", "biosignalsplux", eeg_data_2cm_ver, resolution, "uV")
time_eeg_signal_uv_2cm_ver = bsnb.generate_time(eeg_signal_uv_2cm_ver, sr)
4 - Signal Quality Check - Effect of Electrode placement
4.1 - Raw Data
The figure shows the raw eeg data of electrode positions: O1/O2 and P3/P4:
The following plot illustrates the raw eeg data of O1 vertical and O1/O2 horizontal electrode placement with each 0 / 1 / 2 cm distance:
4.2 - Power Spectrum - SNR
The signal-to-noise ratio (SNR) is compared as a measure of signal quality.
For further explanation on how to extract the band power from the acquired signal please refer to the notebook
EEG - Alpha band extraction
and
EEG - Digital filtering
to read more on noise reduction.
In this case there is no filter applied !
# Time window of closed eyes
t_closed_start = 0 # lower limit of time window (s)
sample_closed_start = t_closed_start*sr
t_closed_end = 60 # Upper limit of time window (s)
sample_closed_end = t_closed_end*sr
4.2.1 - Generation of Power Spectrum by Fast Fourier Transform (FFT) and Welchs Method
A - Electrode Position O1/O2
#Time Windows for Welchs method
win = 4 * sr # 4 seconds time windows.
#FFT with time windows using scipy.signal.welch
freq_axis, power_spect = welch(eeg_signal_uv[sample_closed_start:sample_closed_end], sr, nperseg=win)
B - P3/P4 Segment
#FFT with time windows using scipy.signal.welch
#A: P3/P4 Segment:
freq_axis_p, power_spect_p = welch(eeg_signal_uv_p[sample_closed_start:sample_closed_end], sr, nperseg=win)
C - O1/O2 Horizontal Segment
#FFT with time windows using scipy.signal.welch
#B:O1/O2 horizontal Segment:
freq_axis_0cm_hor, power_spect_0cm_hor = welch(eeg_signal_uv_0cm_hor[sample_closed_start:sample_closed_end], sr, nperseg=win)
freq_axis_1cm_hor, power_spect_1cm_hor = welch(eeg_signal_uv_1cm_hor[sample_closed_start:sample_closed_end], sr, nperseg=win)
freq_axis_2cm_hor, power_spect_2cm_hor = welch(eeg_signal_uv_2cm_hor[sample_closed_start:sample_closed_end], sr, nperseg=win)
D - O1/O2 Vertical Segment
#FFT with time windows using scipy.signal.welch
#C:O1 vertical Segment:
freq_axis_0cm_ver, power_spect_0cm_ver = welch(eeg_signal_uv_0cm_ver[sample_closed_start:sample_closed_end], sr, nperseg=win)
freq_axis_1cm_ver, power_spect_1cm_ver = welch(eeg_signal_uv_1cm_ver[sample_closed_start:sample_closed_end], sr, nperseg=win)
freq_axis_2cm_ver, power_spect_2cm_ver = welch(eeg_signal_uv_2cm_ver[sample_closed_start:sample_closed_end], sr, nperseg=win)
Defining the Alpha Frequency Band:
#Define Frequency Band limits:
freq_low_cutoff = 8 #lower limit for alpha band
freq_high_cutoff = 12 #Upper limit for alpha band
A - Electrode Position O1/O2
#Find the intersection Values of the alpha band in the frequency vector
idx_alpha = logical_and(freq_axis >= freq_low_cutoff, freq_axis <= freq_high_cutoff)
B - P3/P4 Segment
#Find the intersection Values of the alpha band in the frequency vector
#A: P3/P4 Segment:
idx_alpha_p = logical_and(freq_axis_p >= freq_low_cutoff, freq_axis_p <= freq_high_cutoff)
C - O1/O2 Horizontal Segment
#Find the intersection Values of the alpha band in the frequency vector
#B:O1/O2 horizontal Segment:
idx_alpha_0cm_hor = logical_and(freq_axis_0cm_hor >= freq_low_cutoff, freq_axis_0cm_hor <= freq_high_cutoff)
idx_alpha_1cm_hor = logical_and(freq_axis_1cm_hor >= freq_low_cutoff, freq_axis_1cm_hor <= freq_high_cutoff)
idx_alpha_2cm_hor = logical_and(freq_axis_2cm_hor >= freq_low_cutoff, freq_axis_2cm_hor <= freq_high_cutoff)
D - O1/O2 Vertical Segment
#Find the intersection Values of the alpha band in the frequency vector
#C:O1 vertical Segment:
idx_alpha_0cm_ver = logical_and(freq_axis_0cm_ver >= freq_low_cutoff, freq_axis_0cm_ver <= freq_high_cutoff)
idx_alpha_1cm_ver = logical_and(freq_axis_1cm_ver >= freq_low_cutoff, freq_axis_1cm_ver <= freq_high_cutoff)
idx_alpha_2cm_ver = logical_and(freq_axis_2cm_ver >= freq_low_cutoff, freq_axis_2cm_ver <= freq_high_cutoff)
4.2.2 -Extraction of Alpha and Total Band Power from the Power Spectrum
A - Electrode Position O1/O2
#Frequency Resolution
freq_res = freq_axis[1] - freq_axis[0]
#Compute the Absolute Power with numpy.trapz:
alpha_power = trapz(power_spect[idx_alpha],dx=freq_res)
total_power = trapz(power_spect,dx=freq_res)
B - P3/P4 Segment
#A: P3/P4 Segment:
#Frequency Resolution
freq_res_p = freq_axis_p[1] - freq_axis_p[0]
#Compute the Absolute Power with numpy.trapz:
alpha_power_p = trapz(power_spect_p[idx_alpha_p],dx=freq_res_p)
total_power_p = trapz(power_spect_p,dx=freq_res_p)
C - O1/O2 Horizontal Segment
#B:O1/O2 horizontal Segment:
#Frequency Resolution
freq_res_0cm_hor = freq_axis_0cm_hor[1] - freq_axis_0cm_hor[0]
freq_res_1cm_hor = freq_axis_1cm_hor[1] - freq_axis_1cm_hor[0]
freq_res_2cm_hor = freq_axis_2cm_hor[1] - freq_axis_2cm_hor[0]
#Compute the Absolute Power with numpy.trapz:
alpha_power_0cm_hor = trapz(power_spect_0cm_hor[idx_alpha_0cm_hor],dx=freq_res_0cm_hor)
total_power_0cm_hor = trapz(power_spect_0cm_hor, dx = freq_res_0cm_hor)
alpha_power_1cm_hor = trapz(power_spect_1cm_hor[idx_alpha_1cm_hor],dx=freq_res_1cm_hor)
total_power_1cm_hor = trapz(power_spect_1cm_hor, dx = freq_res_1cm_hor)
alpha_power_2cm_hor = trapz(power_spect_2cm_hor[idx_alpha_2cm_hor],dx=freq_res_2cm_hor)
total_power_2cm_hor = trapz(power_spect_2cm_hor, dx = freq_res_2cm_hor)
D - O1/O2 Vertical Segment
#C:O1 vertical Segment:
#Frequency Resolution
freq_res_0cm_ver = freq_axis_0cm_ver[1] - freq_axis_0cm_ver[0]
freq_res_1cm_ver = freq_axis_1cm_ver[1] - freq_axis_1cm_ver[0]
freq_res_2cm_ver = freq_axis_2cm_ver[1] - freq_axis_2cm_ver[0]
#Compute the Absolute Power with numpy.trapz:
alpha_power_0cm_ver = trapz(power_spect_0cm_ver[idx_alpha_0cm_ver],dx=freq_res_0cm_ver)
total_power_0cm_ver = trapz(power_spect_0cm_ver, dx = freq_res_0cm_ver)
alpha_power_1cm_ver = trapz(power_spect_1cm_ver[idx_alpha_1cm_ver],dx=freq_res_1cm_ver)
total_power_1cm_ver = trapz(power_spect_1cm_ver, dx = freq_res_1cm_ver)
alpha_power_2cm_ver = trapz(power_spect_2cm_ver[idx_alpha_2cm_ver],dx=freq_res_2cm_ver)
total_power_2cm_ver = trapz(power_spect_2cm_ver, dx = freq_res_2cm_ver)
4.2.3 Calculation of Signal-to-Noise ratio for alpha band power:
The Signal-to-Noise ratio is applied as a measure of signal quality. It is defined as the ratio of signal power to noise power where a high SNR value refers to a signal with low noise and a low SNR value refers to a signal with high noise.
A - Electrode Position O1/O2
#Calculating the SNR:
snr = alpha_power / total_power
B - P3/P4 Segment
#A: P3/P4 Segment:
snr_p = alpha_power_p / total_power_p
C - O1/O2 Horizontal Segment
#B:O1/O2 horizontal Segment:
snr_0cm_hor = alpha_power_0cm_hor / total_power_0cm_hor
snr_1cm_hor = alpha_power_1cm_hor / total_power_1cm_hor
snr_2cm_hor = alpha_power_2cm_hor / total_power_2cm_hor
D - O1/O2 Vertical Segment
#C:O1 vertical Segment:
snr_0cm_ver = alpha_power_0cm_ver / total_power_0cm_ver
snr_1cm_ver = alpha_power_1cm_ver / total_power_1cm_ver
snr_2cm_ver = alpha_power_2cm_ver / total_power_2cm_ver
For measuring the alpha band power in the posterior part of the brain, higher Signal-to-noise ratio was calculated with a value of 0.67 for an EEG signal acquisition in the parietal lobe (P3/P4) compared to a value of 0.49 measured in the occipital lobe (O1/O2) using 3 cm distance between the electrodes. For distances below 3 cm low SNR values with values between 0.15 - 0.29 were calculated for both horizontal as well as vertical electrode positioning.
This Jupyter Notebook showed how different electrode positions can affect the quality of the EEG signal as well as how to measure the quality calculating the SNR. Based on the measured SNR values the optimal electrode position for the detection of alpha waves could be defined as P3/P4 in the parietal lobe.
However, it is important to consider that despite the same experimental conditions for each electrode position the calculated SNRs might vary due to surrounding noise which could not be removed or different electrode stability on the scalp. To read more on artefacts influencing the signal refer to the notebook
Digital Filtering - EEG
.
We hope that you have enjoyed this guide.
biosignalsnotebooks
is an environment in continuous expansion, so don"t stop your journey and learn more with the remaining
Notebooks
!